package com.wei.czz.framework.job;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.admin.user.UserMessageEnum;
import com.wei.czz.common.enums.blog.BlogStatsFlowEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.TimeUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.framework.common.handler.redis.RedisZSetHandler;
import com.wei.czz.framework.blog.entity.BlogEntity;
import com.wei.czz.framework.blog.entity.BlogStatsEntity;
import com.wei.czz.framework.blog.entity.BlogStatsFlowEntity;
import com.wei.czz.framework.blog.service.BlogService;
import com.wei.czz.framework.blog.service.BlogStatsFlowService;
import com.wei.czz.framework.blog.service.BlogStatsService;
import com.wei.czz.framework.blog.entity.BlogIssueEntity;
import com.wei.czz.framework.admin.entity.UserMessageEntity;
import com.wei.czz.framework.blog.service.BlogIssueService;
import com.wei.czz.framework.admin.service.UserMessageService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-05-24 23:28:00
 * className: BlogJob 博客定时器类
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class BlogJob {

    public static final Logger log = LoggerFactory.getLogger(BlogJob.class);

    private final BlogService blogService;

    private final BlogIssueService blogIssueService;

    private final BlogStatsService blogStatsService;

    private final BlogStatsFlowService blogStatsFlowService;

    private final UserMessageService userMessageService;

    private final RedisHashHandler redisHashHandler;

    private final RedisZSetHandler redisZSetHandler;

    private final RedisHandler redisHandler;

    /**
     * 每个小时更新一次博客热门状态
     * 每个小时的第二分钟执行一次
     *  如
     *  2022-02-25 22:02:00
     *  2022-02-25 23:02:00
     *  2022-02-26 00:02:00
     *  2022-02-26 01:02:00
     *  2022-02-26 02:02:00
     */
    @Scheduled(cron = "0 2 0/1 * * ?")
    public void updateBlogHotStatus() {
        log.info("开始批量更新博客热门状态定时器业务");

        long now = System.currentTimeMillis();

        // 查询Redis缓存，获取今日浏览次数满足热门博客条件的博客id列表
        Set<String> dayBlogIdSet = redisZSetHandler.rangeByScore(RedisConstant.DAY_BLOG_VIEW_ZSET, Constant.DAY_HOT_VIEW, now);

        // 查询Redis缓存，获取这个月浏览次数满足热门博客条件的博客id列表
        Set<String> monthBlogIdSet = redisZSetHandler.rangeByScore(RedisConstant.MONTH_BLOG_VIEW_ZSET, Constant.MONTH_HOT_VIEW, now);
        // 合并博客id
        dayBlogIdSet.addAll(monthBlogIdSet);
        if (!dayBlogIdSet.isEmpty()) {
            Date date = new Date(now);

            /*
                批量更新已发布博客
             */
            List<BlogIssueEntity> blogIssueList = dayBlogIdSet.stream()
                    .map(blogId -> {
                        BlogIssueEntity blogIssue = new BlogIssueEntity();
                        blogIssue.setBlogId(Long.parseLong(blogId))
                                .setHotStatus(CommonEnum.ZERO.getValue())
                                .setUpdateTime(date)
                                .setUpdateUserId(CommonEnum.ZERO.getLongValue());
                        return blogIssue;
                    })
                    .collect(Collectors.toList());
            blogIssueService.batchUpdateBlogIssue(blogIssueList);


            LambdaQueryWrapper<BlogEntity> blogLambdaQueryWrapper = new LambdaQueryWrapper<>();
            // 查询 用户id、博客标题字段
            blogLambdaQueryWrapper.select(BlogEntity::getUserId, BlogEntity::getTitle);
            // 匹配 博客id 字段
            blogLambdaQueryWrapper.eq(BlogEntity::getId, dayBlogIdSet);
            // 查询数据库系统博客基本表，根据博客id批量匹配博客基本信息
            List<BlogEntity> blogList = blogService.getBlogList(
                    dayBlogIdSet.stream().map(Long::parseLong).collect(Collectors.toList())
            );
            // 根据用户id进行分组操作
            Map<Long, List<BlogEntity>> userBlogMap = blogList.stream().collect(Collectors.groupingBy(BlogEntity::getUserId));

            List<UserMessageEntity> userMessageList = new ArrayList<>();

            StringBuilder sb = new StringBuilder();

            String expireTime = TimeUtils.format(TimeUtils.endTimeOnThisMonth());
            for (Map.Entry<Long, List<BlogEntity>> blogEntry : userBlogMap.entrySet()) {
                // 清空字符串缓存
                sb.delete(0, sb.length());

                sb.append("您的");
                blogList = blogEntry.getValue();
                for (BlogEntity blog : blogList) {
                    sb.append('’').append(blog.getTitle()).append("‘,");
                }
                // 删除最后一个‘,’字符
                sb.deleteCharAt(sb.length() - 1);
                sb.append("博客被系统升级为热门博客，有效期至当前月底最后一天（");
                sb.append(expireTime);
                sb.append("），请查看。");

                UserMessageEntity userMessage = new UserMessageEntity();
                userMessage.setGetUserId(blogEntry.getKey())
                        .setSendUserId(CommonEnum.ZERO.getLongValue())
                        .setSort(UserMessageEnum.SYSTEM_MSG.getValue())
                        .setReadFlag(UserMessageEnum.READ_NO.getValue())
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setTitle("博客热门通知")
                        .setMessage(sb.toString())
                        .setUpdateTime(date)
                        .setCreateTime(date);
                userMessageList.add(userMessage);
            }
            // 操作数据库用户消息表，批量新增用户消息信息
            boolean bool = userMessageService.batchSaveUserMessage(userMessageList);
            if (!bool) {
                throw new CzzException("批量保存用户消息信息失败，请务必及时处理");
            }

            // 操作Redis缓存，删除今日浏览次数以达到热门博客的记录
            redisZSetHandler.removeRangeByScore(RedisConstant.DAY_BLOG_VIEW_ZSET, Constant.DAY_HOT_VIEW, now);
            // 操作Redis缓存，删除这个月浏览次数以达到热门博客的记录
            redisZSetHandler.removeRangeByScore(RedisConstant.MONTH_BLOG_VIEW_ZSET, Constant.MONTH_HOT_VIEW, now);

        }

        log.info("批量更新博客热门状态定时器业务结束");
    }

    /**
     * 每三十分钟更新最近有变化的博客缓存
     * 每三十分钟的第零秒执行一次
     * 如：
     *  2022-02-27 11:30:00
     *  2022-02-27 12:00:00
     *  2022-02-27 12:30:00
     *  2022-02-27 13:00:00
     *  2022-02-27 13:30:00
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void updateBlogCache() {
        log.info("定时任务（cron=‘0 1 0/1 * * ?’）开始更新博客缓存信息");
        // 查询Redis缓存，获取最新有修改的博客id
        Set<String> blogIdSet = redisHashHandler.keys(RedisConstant.UPDATE_BLOG_MAP);
        if (blogIdSet != null && blogIdSet.size() > 0) {
            // 查询数据库系统博客基本表，获取博客基本信息列表
            List<BlogEntity> blogList = blogService.getBlogList(
                    blogIdSet.stream().map(Long::parseLong).collect(Collectors.toList())
            );
            if (!blogList.isEmpty()) {
                String[] blogIds = new String[blogList.size()];
                // 博客基本信息列表 List转Map
                Map<String, BlogEntity> blogMap = new HashMap<>();
                for (int i = 0; i < blogIds.length; i++) {
                    BlogEntity blog = blogList.get(i);
                    String blogId = blog.getId().toString();

                    blogIds[i] = blogId;
                    blogMap.put(blogId, blog);
                }
                // 操作Redis缓存，批量更新博客基本信息缓存
                redisHashHandler.putAll(CacheKeyUtils.getRedisHashKey(EntityConstant.BLOG), blogMap);
                // 操作Redis缓存，批量删除最新有更新的博客记录缓存
                redisHashHandler.delete(RedisConstant.UPDATE_BLOG_MAP, blogIds);
            }
        }
        log.info("定时任务（cron=‘0 1 0/1 * * ?’）更新博客缓存信息结束");
    }

    /**
     * 每个月定时清空所有热门博客状态
     * 每个月开始时间执行一次（开始时间：零点零分零秒）
     * 如：
     *  2021-10-01 00:00:00
     *  2021-11-01 00:00:00
     *  2021-12-01 00:00:00
     *  2022-01-01 00:00:00
     *  2022-02-01 00:00:00
     */
    @Scheduled(cron = "0 0 0 1 1/1 ?")
    public void clearHotBlog() {
        Calendar calendar = Calendar.getInstance();
        // 时间回退一个月
        calendar.add(Calendar.MONTH, -1);
        Date date = calendar.getTime();

        DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月");

        String time = dateFormat.format(date);
        log.info("定时任务（cron=‘0 0 0 1 1/1 ?’）开始清空时间为{}的所有热门博客为正常博客定时器业务", time);

        /*
            清理已发布博客的热门状态
         */
        blogIssueService.resetIssueBlogHotStatus();

        // 操作Redis缓存，清空一个月的博客浏览量
        redisHandler.delete(RedisConstant.MONTH_BLOG_VIEW_ZSET);

        log.info("定时任务（cron=‘0 0 0 1 1/1 ?’）清空时间为{}的所有热门博客为正常博客定时器业务结束", time);
    }

    /**
     * 每日零点零分零秒统计上一天博客浏览次数、点赞数、收藏数和评论数
     * 如：
     *  2022-03-04 00:00:00
     *  2022-03-05 00:00:00
     *  2022-03-06 00:00:00
     *  2022-03-07 00:00:00
     *  2022-03-08 00:00:00
     */
    @Transactional
    @Scheduled(cron = "0 0 0 1/1 * ?")
    public void recordBlogStatsOnDay() {
        log.info("定时任务（cron=‘0 0 0 1/1 * ?’）开始统计上一天博客浏览次数业务");

        // 查询数据库博客统计表，获取博客统计信息
        List<BlogStatsEntity> blogStatsList = blogStatsService.getBlogStatsList(null);
        if (!blogStatsList.isEmpty()) {
            Date date = new Date();
            Date[] preDayByDate = TimeUtils.getPreDayByDate(date);

            List<BlogStatsFlowEntity> blogStatsFlowEntityList = blogStatsList.stream()
                .flatMap(blogStats -> {
                    List<BlogStatsFlowEntity> blogStatsFlowList = new ArrayList<>();
                    if (blogStats.getDayViewNum() > 0) {
                        // 博客日浏览次数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.VIEW_TYPE.getValue(),
                                        BlogStatsFlowEnum.DAY_VALUE.getValue(), blogStats.getDayViewNum(), preDayByDate[0],
                                        preDayByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getDayLikeNum() > 0) {
                        // 博客日点赞数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.LIKE_TYPE.getValue(),
                                        BlogStatsFlowEnum.DAY_VALUE.getValue(), blogStats.getDayLikeNum(), preDayByDate[0],
                                        preDayByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getDayCollectNum() > 0) {
                        // 博客日收藏数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COLLECT_TYPE.getValue(),
                                        BlogStatsFlowEnum.DAY_VALUE.getValue(), blogStats.getDayCollectNum(), preDayByDate[0],
                                        preDayByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getDayCommentNum() > 0) {
                        // 博客日评论数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COMMENT_TYPE.getValue(),
                                        BlogStatsFlowEnum.DAY_VALUE.getValue(), blogStats.getDayCommentNum(), preDayByDate[0],
                                        preDayByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }

                    return blogStatsFlowList.stream();
                })
                .collect(Collectors.toList());

            if (!blogStatsFlowEntityList.isEmpty()) {
                /*
                    系统博客日统计列表不为空
                 */
                blogStatsFlowService.batchSaveBlogStatsFlow(blogStatsFlowEntityList);

                // 重置系统博客日统计数据
                blogStatsService.resetBlogStatsOnDay();
            }
        }
        log.info("定时任务（cron=‘0 0 0 1 1/1 ?’）统计上一天博客浏览次数业务结束");
    }

    /**
     * 每月一号零点零分零秒统计上一个月博客浏览次数、点赞数、收藏数和评论数
     * 如：
     *  2022-04-01 00:00:00
     *  2022-05-01 00:00:00
     *  2022-06-01 00:00:00
     *  2022-07-01 00:00:00
     *  2022-08-01 00:00:00
     */
    @Transactional
    @Scheduled(cron = "0 0 0 1 1/1 ?")
    public void recordBlogStatsOnMonth() {
        log.info("定时任务（cron=‘0 0 0 1 1/1 ?’）开始统计上一个月博客浏览次数业务");

        // 查询数据库博客统计表，获取博客统计信息
        List<BlogStatsEntity> blogStatsList = blogStatsService.getBlogStatsList(null);
        if (!blogStatsList.isEmpty()) {
            Date date = new Date();
            Date[] preMonthByDate = TimeUtils.getPreMonthByDate(date);

            List<BlogStatsFlowEntity> blogStatsFlowEntityList = blogStatsList.stream()
                .flatMap(blogStats -> {
                    List<BlogStatsFlowEntity> blogStatsFlowList = new ArrayList<>();
                    if (blogStats.getMonthViewNum() > 0) {
                        // 博客月浏览次数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.VIEW_TYPE.getValue(),
                                        BlogStatsFlowEnum.MONTH_VALUE.getValue(), blogStats.getMonthViewNum(), preMonthByDate[0],
                                        preMonthByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getMonthLikeNum() > 0) {
                        // 博客月点赞数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.LIKE_TYPE.getValue(),
                                        BlogStatsFlowEnum.MONTH_VALUE.getValue(), blogStats.getMonthLikeNum(), preMonthByDate[0],
                                        preMonthByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getMonthCollectNum() > 0) {
                        // 博客月收藏数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COLLECT_TYPE.getValue(),
                                        BlogStatsFlowEnum.MONTH_VALUE.getValue(), blogStats.getMonthCollectNum(), preMonthByDate[0],
                                        preMonthByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getMonthCommentNum() > 0) {
                        // 博客月评论数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COMMENT_TYPE.getValue(),
                                        BlogStatsFlowEnum.MONTH_VALUE.getValue(), blogStats.getMonthCommentNum(), preMonthByDate[0],
                                        preMonthByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }

                    return blogStatsFlowList.stream();
                })
                .collect(Collectors.toList());

            if (!blogStatsFlowEntityList.isEmpty()) {
                /*
                    系统博客日统计列表不为空
                 */
                blogStatsFlowService.batchSaveBlogStatsFlow(blogStatsFlowEntityList);

                // 重置系统博客月统计数据
                blogStatsService.resetBlogStatsOnMonth();
            }
        }
        log.info("定时任务（cron=‘0 0 0 1 1/1 ?’）统计上一个月博客浏览次数业务结束");
    }

    /**
     * 每年一月一号零点零分零秒统计上一年博客浏览次数、点赞数、收藏数和评论数
     */
    @Transactional
    @Scheduled(cron = "0 0 0 1 1 ?")
    public void recordBlogStatsOnYear() {
        log.info("定时任务（cron=‘0 0 0 1 1 ?’）开始统计上一年博客浏览次数、点赞数、收藏数和评论数业务");

        // 查询数据库博客统计表，获取博客统计信息
        List<BlogStatsEntity> blogStatsList = blogStatsService.getBlogStatsList(null);
        if (!blogStatsList.isEmpty()) {
            Date date = new Date();
            Date[] preYearByDate = TimeUtils.getPreYearByDate(date);

            List<BlogStatsFlowEntity> blogStatsFlowEntityList = blogStatsList.stream()
                .flatMap(blogStats -> {
                    List<BlogStatsFlowEntity> blogStatsFlowList = new ArrayList<>();
                    if (blogStats.getYearViewNum() > 0) {
                        // 博客年浏览次数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.VIEW_TYPE.getValue(),
                                        BlogStatsFlowEnum.YEAR_VALUE.getValue(), blogStats.getYearViewNum(), preYearByDate[0],
                                        preYearByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getYearLikeNum() > 0) {
                        // 博客年点赞数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.LIKE_TYPE.getValue(),
                                        BlogStatsFlowEnum.YEAR_VALUE.getValue(), blogStats.getYearLikeNum(), preYearByDate[0],
                                        preYearByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getYearCollectNum() > 0) {
                        // 博客年收藏数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COLLECT_TYPE.getValue(),
                                        BlogStatsFlowEnum.YEAR_VALUE.getValue(), blogStats.getYearCollectNum(), preYearByDate[0],
                                        preYearByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }
                    if (blogStats.getYearCommentNum() > 0) {
                        // 博客年评论数记录
                        BlogStatsFlowEntity blogStatsFlow =
                                new BlogStatsFlowEntity(blogStats.getBlogId(), BlogStatsFlowEnum.COMMENT_TYPE.getValue(),
                                        BlogStatsFlowEnum.YEAR_VALUE.getValue(), blogStats.getYearCommentNum(), preYearByDate[0],
                                        preYearByDate[1], date);

                        blogStatsFlowList.add(blogStatsFlow);
                    }

                    return blogStatsFlowList.stream();
                })
                .collect(Collectors.toList());

            if (!blogStatsFlowEntityList.isEmpty()) {
                /*
                    系统博客年统计列表不为空
                 */
                blogStatsFlowService.batchSaveBlogStatsFlow(blogStatsFlowEntityList);

                // 重置系统博客年统计数据
                blogStatsService.resetBlogStatsOnYear();
            }
        }
        log.info("定时任务（cron=‘0 0 0 1 1 ?’）统计上一年博客浏览次数、点赞数、收藏数和评论数业务结束");
    }

}
